import * as THREE from "../../../three/build/three.module.js"
import {OrbitControls} from "../../../three/examples/jsm/controls/OrbitControls.js"
import { GLTFLoader } from "../../../three/examples/jsm/loaders/GLTFLoader.js";

let renderer, camera, scene, nextFunctions=[];
let earth, plane, rubbishs, bins, gameStatus=0;
let selectedRubbish = {rubbish:null, pos:new THREE.Vector3()};
let mouseOnRubbish = null;

init();
createTextTexture();
createScene();
animate();


window.rubbishs = rubbishs;

function init(){
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(20, window.innerWidth/ window.innerHeight, 0.01, 1000);
    renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });

    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0x227777);
    document.body.appendChild(renderer.domElement);
    camera.position.z = 15;

    // new OrbitControls(camera,renderer.domElement);

    window.scene = scene;
    window.camera = camera;
    window.renderer = renderer;
}
function animate(){
    requestAnimationFrame(animate);
    next();
    render();
}

function render(){
    renderer.render(scene,camera);
}

function next(){
    for(let i = 0; i<nextFunctions.length; i++){
        // console.log("next")
        nextFunctions[i]();
    }
}

function createScene(){
    let textureLoader = new THREE.TextureLoader();
    textureLoader.load('./img/earth.png',function(texture){
        earth = new THREE.Mesh(
            new THREE.SphereBufferGeometry(1.6,80,50),
            new THREE.MeshLambertMaterial({
                map: texture
            })
        );
        earth.position.z = -2;
        scene.add(earth);
        nextFunctions.push(function(){
            earth.rotation.y += 0.02;
        })
    });

    let textureLoader2 = new THREE.TextureLoader();
    textureLoader2.load('./img/sky2.png',function(texture){
        texture.repeat = new THREE.Vector2(16,16);
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        let background = new THREE.Mesh(
            new THREE.PlaneBufferGeometry(40,40),
            new THREE.MeshBasicMaterial({
                map: texture,
                // transparent: true,
                // opacity: 0.7
            })
        );
        background.position.z = -3.;
        scene.add(background);
    });

    plane = new THREE.Mesh(
        new THREE.PlaneBufferGeometry(60,60),
        new THREE.MeshBasicMaterial({opacity:0,transparent:true,alphaTest:0.1})
    );
    scene.add(plane);

    let light = new THREE.AmbientLight(0xffffff,.5);
    scene.add(light);

    let light2 = new THREE.DirectionalLight(0xffffff,.7);
    let lightTarget = new THREE.Object3D();
    lightTarget.position.set(1,-1,-1);
    light2.target=lightTarget;
    scene.add(lightTarget);
    scene.add(light2);

}

function createScene2(){
    createBin();
    createRubbish();
}

function createTextTexture(){
    let canvas = document.createElement(`canvas`);
    // document.body.appendChild(canvas);
    let ctx = canvas.getContext(`2d`);
    
    canvas.width = 128;
    canvas.height = 128*2;
    canvas.style=`position: fixed; z-index: 999; left: 0; top: 150px; rgba(255, 255, 255,0)`;

    canvas.style.background = "rgba(0,0,0,1)";

    ctx.clearRect(0,0,128,128*2);
    ctx.fillStyle = "rgba(255,255,255,.9)";
    ctx.textBaseline = "middle";
    ctx.textAlign = "center";
    ctx.font="20px Georgia";

    ctx.fillText("Hazardous",64,32);
    ctx.fillText("Waste",64,52);

    ctx.fillText("Food Waste",64,32+64);

    ctx.fillText("Recyclable",64,32+64*2);

    ctx.fillText("Residual",64,32+64*3);
    ctx.fillText("Waste",64,52+64*3);

    return canvas;
}

function binTextMesh(){
    let canvas = createTextTexture();
    let texts = [];
    for(let i=0; i<4; i++){
        let texture = new THREE.CanvasTexture(canvas);
        texture.repeat.y = 1/4;
        texture.offset.set(0,.25*(3-i));
        let text= new THREE.Mesh(
            new THREE.PlaneBufferGeometry(), 
            new THREE.MeshBasicMaterial({
                transparent:true,
                map:texture
            })
        );
        let textSize =6;
        text.name = "text"+i;
        text.scale.set(textSize,textSize/2,1);
        // text.position.set(-2.1 + 1.333*i, 2.2, -0.6);
        text.position.set(-.6, 5, 2.5);
        texts.push(text);
        // scene.add(text);
        // texts.add(text);
    }
    // scene.add(texts);
    return texts;
}

function createBin(){
    let texts = binTextMesh();
    let gltfLoader = new GLTFLoader();

    gltfLoader.load('./model/bin.gltf',function(gltf){
        let texture2 = new THREE.TextureLoader().load( "./img2/r1.png" );
        let bin1 = gltf.scene.children[0];
        //window.bin1 = bin1;
        bin1.name = "red";
        bin1.children[0].material.color.set(0xcc2222);
        bin1.children[1].material.color.set(0x333333);
        

        // bin1.scale.setScalar(.14);
        bin1.scale.setScalar(0);
        bin1.rotation.set(0,0,0);
        bin1.position.set(-1.0,1.,-2);
bin1.rotation.z = Math.PI*0.25;
        let bin2 = bin1.clone();
        bin2.name = "green";
        bin2.children[0].material = bin2.children[0].material.clone();
        bin2.children[0].material.color.set(0x22cc22);
        bin2.position.set(-.366,1.366,-2);
        // bin2.position.x += 1.333;
bin2.rotation.z = Math.PI*0.25/3;

        let bin3 = bin2.clone();
        bin3.name = "blue";
        bin3.children[0].material = bin3.children[0].material.clone();
        bin3.children[0].material.color.set(0x2222cc);
        // bin3.position.x += 1.333;
        bin3.position.set(.366,1.366,-2);
bin3.rotation.z = -Math.PI*0.25/3;

        let bin4 = bin3.clone();
        bin4.name = "black";
        bin4.children[0].material = bin4.children[0].material.clone();
        bin4.children[0].material.color.set(0x222222);
        // bin4.position.x += 1.333;
        bin4.position.set(1.0,1.,-2);
bin4.rotation.z = -Math.PI*0.25;

        bins = new THREE.Group();
        bin1.add(texts[0]);
        bin2.add(texts[1]);
        bin3.add(texts[2]);
        bin4.add(texts[3]);
        // console.log(`texts[0]`,texts[0]);
        // console.log(texts[0].getWorldPosition());
        bins.add(bin1,bin2,bin3,bin4);
        scene.add(bins);

        window.bins = bins;
    });
}

function createRubbish(){
    let texture1 = new THREE.TextureLoader().load( "./img2/r1.png" );
    let texture2 = new THREE.TextureLoader().load( "./img2/r2.png" );
    let texture3 = new THREE.TextureLoader().load( "./img2/r3.png" );
    let texture4 = new THREE.TextureLoader().load( "./img2/r4.png" );
    let texture5 = new THREE.TextureLoader().load( "./img2/r5.png" );
    let texture6 = new THREE.TextureLoader().load( "./img2/r6.png" );

    let rubbish1 = new THREE.Mesh(
        //new THREE.BoxBufferGeometry(.5,.5,.5),
        new THREE.PlaneBufferGeometry(0.7,.7),
        new THREE.MeshLambertMaterial({
            transparent:true, 
            map: texture1,
            depthWrite : true,
        })
    );
    rubbish1.binName = "red";
    rubbish1.hintText = `Leakage of acid and heavy metal lead contained in automobile waste batteries into nature can cause soil and water pollution, and eventually cause harm to people.<br/>
    A No. 1 battery rots in the soil, which can make one square meter of land useless.`;
    rubbish1.position.set(-2.5,-2,0);
    let rubbish2 = rubbish1.clone();
    rubbish2.binName = "blue";
    rubbish2.hintText = `Plastic bottles are generally made of food-grade PET, are not easily broken, have high transparency, and are safe to use.`;
    rubbish2.material = new THREE.MeshBasicMaterial({transparent:true, map: texture2, depthWrite : true})
    rubbish2.position.x += 1;
    let rubbish3 = rubbish2.clone();
    rubbish3.binName = "black";
    rubbish3.hintText = `Used tissue is contaminated and cannot be recycled.`;
    rubbish3.material = new THREE.MeshBasicMaterial({transparent:true, map: texture3, depthWrite : true})
    rubbish3.position.x += 1;
    let rubbish4 = rubbish3.clone();
    rubbish4.binName = "green";
    rubbish4.hintText = `The apple core is the part left after the outer layer of the apple is eaten up。`;
    rubbish4.material = new THREE.MeshBasicMaterial({transparent:true, map: texture4, depthWrite : true})
    rubbish4.position.x += 1;
    let rubbish5 = rubbish4.clone();
    rubbish5.binName = "blue";
    rubbish5.hintText = `Waste cans can be recycled through their own recycling, reducing material costs.`;
    rubbish5.material = new THREE.MeshBasicMaterial({transparent:true, map: texture5, depthWrite : true})
    rubbish5.position.x += 1;
    let rubbish6 = rubbish5.clone();
    rubbish6.binName = "black";
    rubbish6.hintText = `Candles are not harmful garbage.`;
    rubbish6.material = new THREE.MeshBasicMaterial({transparent:true, map: texture6, depthWrite : true})
    rubbish6.position.x += 1;
    rubbishs = new THREE.Group();
    rubbishs.add(rubbish1,rubbish2,rubbish3,rubbish4,rubbish5,rubbish6);
    scene.add(rubbishs);

    nextFunctions.push(function(){
        for(let i=0; i<rubbishs.length; i++){
            let r = rubbishs[i];
            if(r.isMouseOn) 
                r.scale.set(2,2,2);
            else
                r.scale.set(1,1,1);
        }
    })
}

function createRay(){
    let raycaster = new THREE.Raycaster();

    function getMousePos(e){ // 发生射线需要的位置, e为鼠标事件
        let mousePos = new THREE.Vector3();
        let rendererSize=renderer.getSize();
        mousePos.set(e.offsetX/rendererSize.x-.5, -(e.offsetY/rendererSize.y-.5));
        mousePos.x *= 2;
        mousePos.y *= 2;
        return mousePos;
    }
    
    renderer.domElement.addEventListener(`mousedown` , function(e){
        if(e.button != 0) return; 
        rayLaunch(e);

        function rayLaunch(e){
            let mousePos = getMousePos(e);
            raycaster.setFromCamera(mousePos, camera);

            let intersection = raycaster.intersectObjects([...rubbishs.children]);
            
            if(intersection.length){
                selectedRubbish.rubbish = intersection[0].object;
                selectedRubbish.pos.copy(selectedRubbish.rubbish.position);
            }
        }
    });

    renderer.domElement.addEventListener(`mouseup` , function(e){
        if(e.button != 0) return; // 如果不是左击, 直接跳出
        if(selectedRubbish.rubbish == null) return;

        rayLaunch(e);

        function rayLaunch(e){
            let mousePos = getMousePos(e);
            let items = []; // 可以点击/受射线影响的对象
            for(let i = 0; i<bins.children.length; i++){
                items.push(...bins.children[i].children);
            }
            raycaster.setFromCamera(mousePos, camera);

            let intersection = raycaster.intersectObjects(items)

            // console.log(intersection);
            if(intersection.length && intersection[0].object.parent.name == selectedRubbish.rubbish.binName){
                selectedRubbish.rubbish.parent.remove(selectedRubbish.rubbish);
                selectedRubbish.rubbish = null;
                gameFinish();
            }else{
                selectedRubbish.rubbish.position.copy(selectedRubbish.pos);
                selectedRubbish.rubbish = null;
            }
        }

    });

    renderer.domElement.addEventListener(`mousemove` , function(e){
        
        if(selectedRubbish.rubbish != null){
            rayLaunchPlane(e);
        }else{
            rayLaunchRubbish(e);
        }

        function rayLaunchPlane(e){
            let mousePos = getMousePos(e);
            raycaster.setFromCamera(mousePos, camera);
            let intersection = raycaster.intersectObjects([plane]);

            if(intersection.length){
                selectedRubbish.rubbish.position.set(intersection[0].point.x,intersection[0].point.y,.2);
            }
        }

        function rayLaunchRubbish(e){
            let mousePos = getMousePos(e);
            raycaster.setFromCamera(mousePos, camera);
            let intersection = raycaster.intersectObjects([...rubbishs.children]);

            if(intersection.length){
                if(mouseOnRubbish != null){
                    mouseOnRubbish.position.z=0;
                    mouseOnRubbish.scale.set(1,1,1);
                }
                mouseOnRubbish = intersection[0].object;
                mouseOnRubbish.position.z=.2;
                mouseOnRubbish.scale.set(2,2,2);
                showHint(mouseOnRubbish.hintText);
            }else{
                if(mouseOnRubbish != null){
                    mouseOnRubbish.position.z=0;
                    mouseOnRubbish.scale.set(1,1,1);
                    mouseOnRubbish = null;
                    hideHint();
                }
            }
        }
    });
    
}

function showHint(str){
    let hintText = document.getElementById("hintText");
    hintText.innerHTML = str;
    let div = document.getElementById("hintBox");
    div.style.display = "block";
}

function hideHint(){
    let div = document.getElementById("hintBox");
    div.style.display = "none";
}

function start(){
    let timeMax = 100;
    let time = 0;
    let newPos = new THREE.Vector3(0,0,7);
    let oldPos = camera.position.clone();

    nextFunctions.push(cameraNext);
    function cameraNext(){
        time ++;
        // console.log(time);
        if(time>timeMax){
            if(time == timeMax+1)
                gameStatus=1;
            return;
        }
        let newP = newPos.clone();
        newP.sub(oldPos);

        newP.multiplyScalar(time/timeMax);
        newP.add(oldPos);
        camera.position.copy(newP);

        renderer.domElement.style.filter = `blur(${20-time/timeMax*20}px)`;
    }

    let div = document.getElementById("gameStart");
    div.style.display = "none";
    let div2 = document.getElementById("textDiv");
    div2.style.display = "block";
}

function gameStart(){

    if(gameStatus==1){
        gameStatus=2;
        createScene2();
        createRay();

        let timeMax = 100;
        let time = 0;
        let newPos = new THREE.Vector3(0,0,17);
        let oldPos = camera.position.clone();
        let div2 = document.getElementById("textDiv");
        div2.style.display = "none";

        nextFunctions.push(cameraNext);
        function cameraNext(){
            time ++;
            if(time>timeMax){
                gameStatus=3;
                return;
            }
            let newP = newPos.clone();
            newP.sub(oldPos);
            newP.multiplyScalar(time/timeMax);
            newP.add(oldPos);
            camera.position.copy(newP);

            if(bins != undefined){
                let firstScale = 0;
                let lastScale = 0.14;
                let scale = (lastScale-firstScale)*(time/timeMax);

                for(let i=0; i<bins.children.length; i++){
                    bins.children[i].scale.setScalar(scale);
                }
            }
            
        }
    }
}

function gameFinish(){
    if(rubbishs.children.length == 0){
        let div = document.getElementById("gamefinish");
        div.style.display = "block";
        renderer.domElement.style.filter = `blur(20px)`;
    }
}

window.gameStart = gameStart;
window.start = start;
window.nextFunctions = nextFunctions;

document.body.addEventListener("click",gameStart);


function test(){
    start();
    gameStatus = 1;
    gameStart();
}
// test();